package io.github.linpeilie.mapstruct;

import io.github.linpeilie.AbstractCachedConverterFactory;
import io.github.linpeilie.BaseMapMapper;
import io.github.linpeilie.BaseMapper;
import org.babyfish.jimmer.meta.ImmutableType;
import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;

public class SpringConverterFactory extends AbstractCachedConverterFactory {

    private final ApplicationContext applicationContext;

    public SpringConverterFactory(final ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public <S, T> BaseMapper<S, T> findMapper(final Class<S> sourceType, final Class<T> targetType) {
        final Class<S> actualSourceType = ImmutableType.tryGet(sourceType) != null? (Class<S>) ImmutableType.get(sourceType).getJavaClass() : sourceType;
        final Class<T> actualTargetType = ImmutableType.tryGet(targetType) != null? (Class<T>) ImmutableType.get(targetType).getJavaClass() : targetType;
        ResolvableType type = ResolvableType.forClassWithGenerics(
            BaseMapper.class, actualSourceType, actualTargetType);
        String[] beanNames = applicationContext.getBeanNamesForType(type);
        if (beanNames.length == 0) {
            return null;
        }
        return (BaseMapper<S, T>) applicationContext.getBean(beanNames[0]);
    }

    @Override
    protected <S> BaseMapMapper findMapMapper(final Class<?> source) {
        final Class<?> actualSourceType = ImmutableType.tryGet(source) != null? (Class<S>) ImmutableType.get(source).getJavaClass() : source;
        ResolvableType type = ResolvableType.forClassWithGenerics(
            BaseMapMapper.class, actualSourceType);
        String[] beanNames = applicationContext.getBeanNamesForType(type);
        if (beanNames.length == 0) {
            return null;
        }
        return (BaseMapMapper) applicationContext.getBean(beanNames[0]);
    }
}
